package com.yinhe.music.yhmusic.play;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Handler;
import android.text.format.DateUtils;
import android.util.Log;

import com.apkfuns.logutils.LogUtils;
import com.hwangjr.rxbus.RxBus;
import com.yinhe.music.event.RxBusEventType;
import com.yinhe.music.yhmusic.application.AppCache;
import com.yinhe.music.yhmusic.db.DataBaseAccessor;
import com.yinhe.music.yhmusic.db.bean.RecentMusicDBEntity;
import com.yinhe.music.yhmusic.enums.PlayModeEnum;
import com.yinhe.music.yhmusic.listener.OnPlayerEventListener;
import com.yinhe.music.yhmusic.log.MLog;
import com.yinhe.music.yhmusic.manager.DialogActivity;
import com.yinhe.music.yhmusic.model.Music;
import com.yinhe.music.yhmusic.music.PlayUtils;
import com.yinhe.music.yhmusic.music.PlayingActivity;
import com.yinhe.music.yhmusic.service.PlayService;
import com.yinhe.music.yhmusic.utils.NetworkUtils;
import com.yinhe.music.yhmusic.utils.Preferences;
import com.yinhe.music.yhmusic.utils.SystemUtils;
import com.yinhe.music.yhmusic.utils.ToastUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import static android.content.Context.AUDIO_SERVICE;
import static android.content.Context.NOTIFICATION_SERVICE;
import static com.yinhe.music.yhmusic.enums.PlayModeEnum.ONE;

public class PlayManager implements IPlayManager, MediaPlayer.OnErrorListener,
        MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, AudioManager.OnAudioFocusChangeListener {

    private PlayService mService;
    private NotificationManager mNotificationManager;
    private static final int NOTIFICATION_ID = 0x111;
    private static final long TIME_UPDATE = 100L;
    private static final long MAX_DURATION = 60 * 60 * 12 * 1000;
    private List<Music> mMusicList = new ArrayList<>();
    private MediaPlayer mPlayer;
    private List<OnPlayerEventListener> listenerList = new ArrayList<>();
    private Music mPlayingMusic;
    private int mPlayingPosition;
    private boolean isPause;
    private long quitTimerRemain;

    private AudioManager mAudioManager;
    private Handler mHandler = new Handler();


    public PlayManager(PlayService service) {
        mService = service;
        mAudioManager = (AudioManager) mService.getSystemService(AUDIO_SERVICE);
        mNotificationManager = (NotificationManager) mService.getSystemService(NOTIFICATION_SERVICE);
        // 【适配Android8.0】给NotificationManager对象设置NotificationChannel
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("notification_id", "notification_name", NotificationManager.IMPORTANCE_LOW);
            mNotificationManager.createNotificationChannel(channel);
        }
        updateMusicList();
    }

    /*
    * 歌曲播放完成监听
    * */
    @Override
    public void onCompletion(MediaPlayer mp) {
        PlayModeEnum mode = PlayModeEnum.valueOf(Preferences.getPlayMode());
        if (mMusicList.isEmpty()) {
            return;
        }

        if (mPlayingPosition >= mMusicList.size()) {
            mPlayingPosition = 0;
        }

        if (mode == ONE) {
            playMusic(mMusicList.get(mPlayingPosition));
        } else {
            next();
        }
        // 听歌记录
        PlayUtils.recordMusic(mPlayingMusic);
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        return true;
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        MLog.info(this, "onPrepared ");
        start();
        for (OnPlayerEventListener listener : listenerList) {
            listener.onChange(getPlayingMusic());
        }
        mHandler.removeCallbacks(mBackgroundRunnable);
        mHandler.postDelayed(mBackgroundRunnable, TIME_UPDATE);
    }

    @Override
    public void onAudioFocusChange(int focusChange) {
        switch (focusChange) {
            case AudioManager.AUDIOFOCUS_LOSS:
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                if (isPlaying()) pause();
                break;
            default:
                break;
        }
    }

    @Override
    public long getDuration() {
        if (mPlayer != null) {
            int duration = mPlayer.getDuration();
            if (duration < 0) duration = 0;
            if (duration > MAX_DURATION) duration = 0;
            return duration;
        }
        if (mMusicList != null && mMusicList.size() > mPlayingPosition)
            return mMusicList.get(mPlayingPosition).getDuration();
        return 0;
    }

    @Override
    public Music getPlayingMusic() {
        return mPlayingMusic;
    }


    @Override
    public int getPlayingProgress() {
        if (mPlayer != null) {
            int curPos = mPlayer.getCurrentPosition();
            if (curPos < 0) curPos = 0;
            if (curPos > MAX_DURATION) curPos = 0;
            return curPos;
        }
        return 0;
    }

    @Override
    public int getPlayingPosition() {
        return mPlayingPosition;
    }

    @Override
    public boolean isPlaying() {
        return mPlayer != null && mPlayer.isPlaying();
    }

    @Override
    public boolean isPause() {
        return mPlayer != null && isPause;
    }

    @Override
    public void playPause() {
        if (isPlaying()) {
            pause();
        } else if (isPause()) {
            resume();
        } else {
            play(getPlayingPosition());
        }
    }

    @Override
    public void playAll(List<Music> mList) {
        if (mService.replacePlayList(mList)) updateMusicList();
        if (!mMusicList.isEmpty()) {
            switchMode();
            showPlaying();
        } else {
            ToastUtils.show("播放列表为空");
        }
    }

    @Override
    public void playPosition(List<Music> musicList, int position) {
        if (musicList.isEmpty()) {
            MLog.debug("hxh", "music list is null");
            return;
        }

        if (mService.replacePlayList(musicList)) {
            MLog.debug("hxh", "replace playList");
            updateMusicList();
        }

        play(position);
    }

    @Override
    public void playMusic(Music music) {
        try {
            initMediaPlayer();
            mPlayingMusic = music;
            String filePath = music.filePath;
            for (OnPlayerEventListener listener : listenerList) {
                listener.onChange(getPlayingMusic());
            }
            if (filePath != null) {
                mPlayer.setDataSource(filePath);
                mPlayer.prepare();
                start();
            } else {
                playOnlineMusic(music);
            }

            if (!mMusicList.contains(music)) mMusicList.add(0, music);
            if (!music.isRadio()) {
                addtoRecent(music);
                RxBus.get().post(RxBusEventType.Recent.PLAY_MUSIC, music);
            }
        } catch (IOException e) {
            LogUtils.e(e);
            ToastUtils.show("播放歌曲不存在");
        }
    }

    private void playOnlineMusic(final Music music) {
        MLog.info(this, "prepareAsync online m=" + music);
        if (!NetworkUtils.isConnectWifi(mService) && Preferences.getIsProtect()) {
            mService.startDialog(music, DialogActivity.FIRST_PLAY);
        } else {
            if (music.isRadio()) {
                PlayUtils.getRadioPlayUrl(music, this::playUrl);
            } else {
                PlayUtils.getMusicPlayUrl(music, this::playUrl);
            }
        }

    }

//    /**
//     * 检查是否可以播放高音质
//     *
//     * @param music
//     */
//    private void setQuality(final Music music) {
//        if (!Preferences.getIsVip()) {
//            if (Preferences.getQuality().equals(HQ) || Preferences.getQuality().equals(SQ)) {
//                MusicUtils.checkSong(music, new MusicUtils.CheckCallBack() {
//                    @Override
//                    public void checkBuy(boolean needBuy) {
//                        if (needBuy) {
//                            Preferences.setQuality(Common);
//                            reqUrl(music);
//                        } else {
//                            reqUrl(music);
//                        }
//                    }
//                });
//            } else {
//                reqUrl(music);
//            }
//        } else {
//            reqUrl(music);
//        }
//    }

//    private void reqUrl(Music music) {
//        MusicUtils.getMusicPlayUrl(music, Preferences.getQuality(), new MusicUtils.CallBack() {
//            @Override
//            public void getMusicInfoDidSuccess(Music song) {
//                playUrl(song);
//            }
//        });
//    }


    private void playUrl(Music music) {
        try {
            mPlayer.setDataSource(music.getUrl());
            mPlayer.prepareAsync();
        } catch (IOException e) {
            LogUtils.e(e);
            ToastUtils.show("播放链接出错");
        }
    }

    @Override
    public int pause() {
        if (!isPlaying()) return -1;
        mPlayer.pause();
        isPause = true;
        mHandler.removeCallbacks(mBackgroundRunnable);
        updateNotification(mPlayingMusic);
        mAudioManager.abandonAudioFocus(this);
        //TODO hxh NoisyReceiver
//        if (mNoisyReceiver != null) {
//            unregisterReceiver(mNoisyReceiver);
//            mNoisyReceiver = null;
//        }
        for (OnPlayerEventListener listener : listenerList) {
            listener.onPlayerPause();
        }
        return mPlayingPosition;
    }

    @Override
    public int resume() {
        if (isPlaying()) return -1;
        start();
        for (OnPlayerEventListener listener : listenerList) {
            listener.onPlayerResume();
        }
        return mPlayingPosition;
    }

    @Override
    public int next() {
        PlayModeEnum mode = PlayModeEnum.valueOf(Preferences.getPlayMode());

        if (mMusicList.size() > 0) {
            switch (mode) {
                case LOOP:
                    mPlayingPosition = mPlayingPosition + 1;
                    break;
                case SHUFFLE:
                    mPlayingPosition = new Random().nextInt(mMusicList.size());
                    break;
                case ONE:
                    return play(mPlayingPosition + 1);
                default:
                    return play(mPlayingPosition + 1);
            }
        } else {
            mPlayingPosition = 0;
        }

        return play(mPlayingPosition);
    }

    @Override
    public int prev() {
        PlayModeEnum mode = PlayModeEnum.valueOf(Preferences.getPlayMode());
        switch (mode) {
            case LOOP:
                return play(mPlayingPosition - 1);
            case SHUFFLE:
                if (mMusicList.size() > 0) {
                    mPlayingPosition = new Random().nextInt(mMusicList.size());
                } else {
                    mPlayingPosition = 0;
                }
                return play(mPlayingPosition);
            case ONE:
                return play(mPlayingPosition - 1);
            default:
                return play(mPlayingPosition - 1);
        }
    }

    @Override
    public void stopPlaying() {
        stop();
        mPlayingMusic = null;
    }

    @Override
    public void seekTo(int msec) {
        if (isPlaying() || isPause()) {
            mPlayer.seekTo(msec);
            for (OnPlayerEventListener listener : listenerList) {
                listener.onPublish(msec);
            }
        }
    }

    @Override
    public void addOnPlayEventListener(OnPlayerEventListener listener) {
        if (listener != null) listenerList.add(listener);
    }

    @Override
    public void removePlayEventListner(OnPlayerEventListener listener) {
        if (listener != null) listenerList.remove(listener);
    }

    @Override
    public void updateMusicList() {
        mMusicList = mService.getPlayList();
        if (mMusicList.isEmpty()) return;
        updatePlayingPosition();
        mPlayingMusic = (mPlayingMusic == null) ? mMusicList.get(mPlayingPosition) : mPlayingMusic;
    }

    private void addtoRecent(Music music) {
        DataBaseAccessor.getInstance().insertSongSyn(new RecentMusicDBEntity(music));
    }

    /**
     * 根据列表中的position播放
     */
    public int play(int position) {
        if (mMusicList.isEmpty()) return -1;
        if (position < 0) {
            position = mMusicList.size() - 1;
        } else if (position >= mMusicList.size()) {
            position = 0;
        }

        mPlayingPosition = position;

        if (mPlayingMusic == mMusicList.get(mPlayingPosition) && mPlayingMusic.getUrl() != null) {
            if (mPlayer == null) playMusic(mMusicList.get(mPlayingPosition));
            showPlaying();
        } else {
            playMusic(mMusicList.get(mPlayingPosition));
            Preferences.saveCurrentSongId(mPlayingMusic.getId());
        }

        return mPlayingPosition;
    }

    /**
     * 删除或下载歌曲后刷新正在播放的本地歌曲的序号
     */
    private void updatePlayingPosition() {
        int position = 0;
        long id = Preferences.getCurrentSongId();
        for (int i = 0; i < mMusicList.size(); i++) {
            if (mMusicList.get(i).getId() == id) {
                position = i;
                break;
            }
        }
        mPlayingPosition = position;
        Preferences.saveCurrentSongId(mMusicList.get(mPlayingPosition).getId());
    }

    private void switchMode() {
        PlayModeEnum mode = PlayModeEnum.valueOf(Preferences.getPlayMode());
        switch (mode) {
            case ONE:
            case LOOP:
                play(0);
                break;
            case SHUFFLE:
                play(new Random().nextInt(mMusicList.size()));
                break;
            default:
                break;
        }
    }

    private void showPlaying() {
        if (mMusicList != null && mPlayingMusic != null) {
            Intent intent = new Intent(AppCache.getContext(), PlayingActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mService.startActivity(intent);
        }
    }

    private synchronized void initMediaPlayer() {
        if (mPlayer != null) {
            mPlayer.stop();
            mPlayer.setOnErrorListener(null);
            mPlayer.setOnPreparedListener(null);
            mPlayer.setOnCompletionListener(null);
            mPlayer.release();
            mPlayer = null;
        }

        mHandler.removeCallbacks(mBackgroundRunnable);

        mPlayer = new MediaPlayer();
        mPlayer.setOnCompletionListener(this);
        mPlayer.setOnPreparedListener(this);
        mPlayer.setOnErrorListener(this);
    }

    private synchronized void start() {
        if (mPlayer == null) return;
        mPlayer.start();
        isPause = false;
        mHandler.post(mBackgroundRunnable);
        updateNotification(mPlayingMusic);
        mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
    }

    private synchronized void stop() {
        if (mPlayer != null) {
            pause();
            stopQuitTimer();
            mPlayer.setOnCompletionListener(null);
            mPlayer.setOnErrorListener(null);
            mPlayer.setOnPreparedListener(null);
            mPlayer.reset();
            mPlayer.release();
            mPlayer = null;
            mNotificationManager.cancel(NOTIFICATION_ID);
            mService.stopSelf();
        }
    }


    private void stopQuitTimer() {
        mHandler.removeCallbacks(mQuitRunnable);
    }

    private void updateNotification(Music music) {
        if (music == null) return;
        Notification mNotification = SystemUtils.createNotification(isPlaying(), mService, music);
        mService.startForeground(NOTIFICATION_ID, mNotification);
        mNotificationManager.notify(NOTIFICATION_ID, mNotification);
    }

    private Runnable mQuitRunnable = new Runnable() {
        @Override
        public void run() {
            quitTimerRemain -= DateUtils.SECOND_IN_MILLIS;
            if (quitTimerRemain > 0) {
                mHandler.postDelayed(this, DateUtils.SECOND_IN_MILLIS);
            } else {
                AppCache.clearStack();
                stop();
            }
        }
    };

    private Runnable mBackgroundRunnable = new Runnable() {
        @Override
        public void run() {
            if (isPlaying()) {
                for (OnPlayerEventListener listener : listenerList) {
                    listener.onPublish(mPlayer.getCurrentPosition());
                }
            }
            mHandler.postDelayed(this, TIME_UPDATE);
        }
    };

}
